package org.toves.checklua.parse;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.toves.checklua.ast.Complaint;
import org.toves.checklua.scan.Token;
import org.toves.checklua.scan.TokenType;


public class TokenStream {
	private List<Token> tokens;
	private int pos;
	private ArrayList<Complaint> errors;
	private LinkedList<ParseStackEntry> parseStack;
	private List<ParseStackEntry> parseStackView;
	
	public TokenStream(List<Token> tokens) {
		this.tokens = tokens;
		this.pos = 0;
		this.errors = new ArrayList<Complaint>();
		this.parseStack = new LinkedList<ParseStackEntry>();
		this.parseStackView = Collections.unmodifiableList(parseStack);
	}
	
	public List<Complaint> getComplaints() {
		return Collections.unmodifiableList(errors);
	}
	
	public boolean isAtLineStart() {
		if (pos == 0) {
			return true;
		} else {
			Token prev = tokens.get(pos - 1);
			Token cur = tokens.get(pos);
			return prev.getLine() != cur.getLine();
		}
	}
	
	public Token peek() {
		return tokens.get(pos);
	}
	
	public Token peekThenAdvance() {
		Token ret = peek();
		advance();
		return ret;
	}
	
	public Token advanceThenPeek() {
		advance();
		return peek();
	}
	
	public void pushBack() {
		if (pos >= 0) pos--;
	}
	
	public void advance() {
		if (pos < tokens.size() - 1) pos++;
	}

	public Token chomp(TokenType expect, String msg) {
		Token t = peekThenAdvance();
		if (t.getTokenType() != expect) {
			error(t, msg);
		}
		return t;
	}
	
	public void error(Token loc, String msg) {
		Complaint err = Complaint.createError(loc, msg);
		errors.add(err);
		throw new ParseException(err);
	}
	
	public void pushStack(ParseStackEntry value) {
		parseStack.addFirst(value);
	}
	
	public ParseStackEntry peekStack() {
		return parseStack.get(0);
	}
	
	public ParseStackEntry popStack() {
		return parseStack.removeFirst();
	}
	
	public List<ParseStackEntry> getStack() {
		return parseStackView;
	}
}
